package portal.manager.servlet;

import static portal.manager.PortalManagerUtils.getPage;
import static portal.manager.PortalManagerUtils.getPortalPanels;
import static portal.manager.PortalManagerUtils.getTemplate;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.osgi.framework.BundleContext;

import portal.PortalManagerAction;
import portal.PortalPanel;
import portal.manager.data.Page;
import portal.manager.data.Template;
import portal.manager.data.template.TemplateVariableEx;
import portal.manager.templator.MiniTemplator;
import portal.manager.templator.MiniTemplator.VariableNotDefinedException;


@SuppressWarnings("serial")
public class PortalManagerServlet extends HttpServlet {
	
	
	static final boolean DEBUG = false;

	private Map<String,PortalManagerAction> actionMap = new HashMap<String,PortalManagerAction>(100);

	private MessageFormat fmt = new MessageFormat("/{0}/{1}/{2}");

	private BundleContext bundleContext ;
	
	//private Logger log = Logger.getAnonymousLogger();
	private Logger logger = Logger.global;
	
	/**
	 * 
	 */
	public PortalManagerServlet( BundleContext context ) {
		super();
		
		bundleContext = context;
		
	}

	

	@Override
	public void init() throws ServletException {
		super.init();

		actionMap.put( "service", new PortalManagerAction() {

			public void execute( String service, HttpServletRequest req,	HttpServletResponse resp) throws Exception {
				executePage( service, req, resp );
			}
		});
		actionMap.put( "template", new PortalManagerAction() {

			public void execute( String service, HttpServletRequest req,	HttpServletResponse resp) throws Exception {
				executeTemplate( service, req, resp );
			}
		});

	}



	@Override
	protected void doGet( HttpServletRequest req, HttpServletResponse resp) 	throws ServletException, IOException {
		
		try {

			
		
			Object[] params = fmt.parse(req.getRequestURI());

			assert params!=null;
			assert params.length>=2;
			
			if( null==params || params.length<2 ) {
				final String msg = MessageFormat.format("request {0} parsing failed!", req.getRequestURI());

				logger.severe( msg );
				
				throw new IllegalStateException( msg );
			}
			
			PortalManagerAction action = actionMap.get( params[1] );
			
			if( null==action ) {
				final String msg = MessageFormat.format("action {0} not found!", params[1]);

				logger.severe( msg );
				
				throw new IllegalStateException( msg );
			}
			
			action.execute( (String)params[2], req, resp);

if( DEBUG ) {			
			resp.getWriter().printf(
					"getRequestURI=%s\ngetRequestURL=%s\ngetRealPath('/')=%s\ngetResource()=%s\n%s\n",
					req.getRequestURI(),
					req.getRequestURL().toString(),
					getServletContext().getRealPath("/"),
					getServletContext().getResource("/WebContent/portal/templates/test_ContentPane.html"),
					new File(".").getAbsolutePath()
					);
			
			resp.getWriter().printf(
					"param[0]=%s\nparams[1]=%s\n",
					params[0],
					params[1]
					);
}			

		} catch (Exception e) {

			e.printStackTrace( resp.getWriter() );
		}
		
	}

	/**
	 * 
	 * @param panel
	 * @return
	 * @throws Exception
	 */
	private String getPanelContent( PortalPanel panel )  {

		try {

			java.io.BufferedReader br = new java.io.BufferedReader(panel.getPanelContent(), 4096);
		
			StringBuilder sb = new StringBuilder();
		
			for( int c;  (c = br.read())!=-1 ; sb.append((char)c) );

			return sb.toString();

		} catch (Throwable e) {
			logger.log( Level.WARNING, "getPanelContent", e );
		}
		
		return "";
	}

	/**
	 * 
	 * @param var
	 * @param t
	 * @param value
	 * @throws Exception 
	 */
	private void processConstant( Page.Variable var, MiniTemplator t, String value ) throws Exception {
		
		t.setVariable( var.getName(), value );

		if( var.isBlock() ) {
			logger.log( Level.WARNING, "variable {0} is a block but have a constant value associated", var.getName() );
			
			t.addBlock( var.getName() );
			
		}
		
	}

	/**
	 * 
	 * @param var
	 * @param t
	 * @throws Exception
	 */
	private void processPanelsContent( Page.Variable var, MiniTemplator t ) throws Exception {
		
		PortalPanel[] panels = getPortalPanels( bundleContext, var.getValue() );
		
		if( panels.length == 0 ) return;
		
		if( var.isBlock() ) {
			
			for( PortalPanel pp : panels ) {

				t.setVariable( var.getName(), getPanelContent(pp) );
				t.addBlock( var.getName() );
			}
			
		}
		else {
			
			if( panels.length > 1 ) 
				logger.log( Level.WARNING, "variable {0} isn't a block but have more that one panel associated. the first one will be used", var.getName() );
			
			t.setVariable( var.getName(), getPanelContent(panels[0]));
			
		}
		
	}
	
	/**
	 * 
	 * @param pageName
	 * @param req
	 * @param resp
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private void executePage( String pageName, HttpServletRequest req, HttpServletResponse resp ) throws Exception {
		
		Page p = getPage(bundleContext, pageName);
		
		final String path = "/WebContent" + p.getSource();
		
		java.io.InputStream is = getServletContext().getResourceAsStream(path);
		
		if( null==is ) {
			final String msg = MessageFormat.format("unresolved resource path {0}", path);
			
			logger.severe(msg);
			throw new IllegalStateException( msg );
		}
		
		MiniTemplator t = new MiniTemplator( new InputStreamReader(is) );

		t.setVariable("title", p.getTitle(), true);
		
		Pattern constant_pattern = Pattern.compile("\"(.*)\"");
		
		for( Page.Variable var: (List<Page.Variable>) p.getVariables() ) {
			
			Matcher constant_matcher = constant_pattern.matcher(var.getValue());
			
			if( constant_matcher.matches() ) {
				processConstant(var, t, constant_matcher.group(1) );
			}
			else {
				processPanelsContent(var, t);
			}
		}
		
		t.generateOutput (resp.getWriter());
	}

	/**
	 * 
	 * @param templateName
	 * @param req
	 * @param resp
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private void executeTemplate( String templateName, HttpServletRequest req, HttpServletResponse resp ) throws Exception {
		
		Template tpl = getTemplate(bundleContext, templateName);
		
		final String path = "/WebContent" + tpl.getSource();
		
		java.io.InputStream is = getServletContext().getResourceAsStream(path);
		
		if( null==is ) {
			final String msg = MessageFormat.format("unresolved resource path {0}", path);
			
			logger.severe(msg);
			throw new IllegalStateException( msg );
		}
		
		MiniTemplator t = new MiniTemplator( new InputStreamReader(is) );

		t.setVariable("title", "template: ".concat(templateName), true);
		
		Pattern pattern_nested_var = Pattern.compile("(\\w*)[.](\\w*)");
		
		for( TemplateVariableEx var: (List<TemplateVariableEx>) tpl.getVariables() ) {
	
			StringBuilder value = new StringBuilder();
	
			if( pattern_nested_var.matcher(var.getName()).matches() ) {
				String def = var.getDefaultValue();
				
				if( null!=def ) {
					t.setVariable(var.getName(), def);
				}
				continue;
			}
			
			if( var.isCodeModule() ) {
			
				value.append( "console.debug( 'code module ' + ")
					.append('\'')
					.append(var.getName())
					.append('\'')
					.append( (var.isBlock()) ? " + ' block '" : "")
					.append( ");");
			} else {

				value.append("<div style='")
						.append("clear:left;")
						.append("'>")
						.append("<table style='")
						//.append("border-color:black;").append("color:white;")
						.append("font-family: monospace;").append("font-size: medium;").append("text-align: center;")
						//.append("border-style: outset;").append("border:thin;")
						.append("height:100%;").append("vertical-align: middle;")						
						.append("margin-left:auto;").append("margin-right:auto;")
						.append("'>")
						.append( "<tr>")
						.append( "<td>"	)
						.append( "<b>").append( "Name: " ).append( "</b>")
						.append( var.getName() ).append( "&nbsp;")
						.append( "</td>")
						.append( "<td>")
						.append( "<b>").append( "Description: " ).append( "</b>")
						.append( "<i>")
						.append( var.getDescription() ).append( "&nbsp;")
						.append( "</i>")
						.append( "</td>")
						.append( "<td>")
						.append( "<b>").append( "cardinality: " ).append( "</b>")
						.append( (var.isBlock()) ? "[0,n]" : "[0,1]" )
						.append( "</td>")
						.append("</tr></table>")
						.append( "</div>");
			}
				
			t.setVariable( var.getName(), value.toString() );
			if( var.isBlock() ) {
				t.addBlock(var.getName());
			}
				
		}
		t.generateOutput (resp.getWriter());
	}
	
}
